/*
Copyright 2011, CSE Shareware Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, 
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, 
   this list of conditions and the following disclaimer in the documentation 
   and/or other materials provided with the distribution.
 * Neither the name of CSE Shareware Foundation nor the names of its contributors 
   may be used to endorse or promote products derived from this software without 
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "CseApi_.h"

#ifndef CLOSE_REF_CHECK
  extern TInt32 gTotalCseObjCount;
#endif

// Following define TCseObj
//==============================================================================
STATIC TCseException LogObjBuildErr()
{
    return LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("illegal CSE object build flag"));
}

// format for CSE object build
//------------------------------------------------------------------------------
// v: CSE-variant i: CSE-int  w: CSE-wint  f: CSE-float  s: CSE-str   S: N-str
// t: CSE-tier    T: N-tier   b: CSE-buff  B: N-buff     d: CSE-dict  D: N-dict
//
// %#: CSE-ID     %@: CSE-Notator    %-: CSE-weak    %+: CSE-strong
//
// (: CSE-tier begin           ): CSE-tier end
// [: CSE-buff begin           ]: CSE-buff end
// {: CSE-dict begin           }: CSE-dict end
// <: CSE-notator begin        >: CSE-notator end
// <>: CSE-instance
STATIC TXchar BuildOneCseObj(TStolenObj& owner, TXchar prefix, TXchar flag, va_list& pArg)
{
    if (_T('%') == prefix)
    {
        if (_T('#') == flag)         // CSE id
        {
            TCharArray sObj(va_arg(pArg,const TXchar *));
            owner.bind(CseId_NewEx(sObj));
        }
        else if (_T('@') == flag)    // CSE notator
            owner.bind(CseNotator_new(va_arg(pArg,CseObj)));
        else if (_T('+') == flag)    // CSE strong
            owner.bind(CseStrong_new(va_arg(pArg,CseObj)));
        else if (_T('-') == flag)    // CSE weak
            owner.bind(CseWeak_new(va_arg(pArg,CseObj)));

        // %c: int8    %C: uint8   %h: int16  %H: uint16  %d: int32  %D: uint32
        // %w: int64   %W: uint64  %f: float  %F: double  %i: TInt   %I: TUint
        // %u: wchar   %U: wchar*  %x: TXchar %X: TXchar* %V: void*
        else owner.bind(CseInstance_MapVar(flag,pArg));
    }
        
    else if (_T('v') == flag)    // CSE variant
        owner.bind(Cse_IncRefEx(va_arg(pArg,CseObj)));
    else if (_T('i') == flag)    // CSE int
        owner.bind(CseInt_new(va_arg(pArg,TInt)));
    else if (_T('s') == flag)    // CSE str
        owner.bind(CseStr_new(TCharArray(va_arg(pArg,const TXchar *))));
    else if (_T('S') == flag)    // CSE N-str
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner.bind(CseStr_new(TCharArray(va_arg(pArg,const TXchar *),i)));
    }
    else if (_T('t') == flag)    // CSE tier
        owner.bind(CseTier_new(0));
    else if (_T('T') == flag)    // CSE N-tier
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner.bind(CseTier_new(i));
    }
    else if (_T('b') == flag)    // CSE buff
        owner.bind(CseBuff_new(0));
    else if (_T('B') == flag)    // CSE N-buff
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner.bind(CseBuff_new(i));
    }
    else if (_T('d') == flag)    // CSE dict
        owner.bind(CseDict_new(8));
    else if (_T('D') == flag)    // CSE N-dict
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner.bind(CseDict_new(i));
    }
    else if (_T('w') == flag)    // CSE wint
        owner.bind(CseWint_new(va_arg(pArg,TInt64)));
    else if (_T('f') == flag)    // CSE float
		owner.bind(CseFloat_new(va_arg(pArg,TDouble)));

    else if (_T('[') == flag || _T('{') == flag || _T('(') == flag || _T('<') == flag)
    {
        owner.bind(CseBuff_new(0));  // CSE buff, dict, tier, notator
        return flag;
    }
    else if (_T(']') == flag || _T('}') == flag || _T(')') == flag || _T('>') == flag)
        return flag;             // go back to uplevel

    else throw LogObjBuildErr();

    return _T('\0');
}

TCseObj::TCseObj()
{
    m_data = dummy;
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(CseObj obj)
{
    if (obj == NULL) obj = dummy;
    m_data = Cse_IncRefEx(obj);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TCseObj& obj)
{
    m_data = Cse_IncRefEx(obj.m_data);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

STATIC TInt CseNum_AsInt(CseObj obj)
{
    int tp = CSE_TYPE(obj);
    if (dtInt == tp)
        return obj->iValue;
    else if (dtWint == tp)
        return (TInt) obj->wValue;
    else if (dtFloat == tp)
        return (TInt) obj->fValue;
    else return (TInt) obj;
}

STATIC CseObj SetupBuildResult(const TXchar flag, CseObj buff)
{
    ASSERT_TRUE(CSE_TYPE(buff) == dtBuff);

    if (_T(']') == flag)
        return Cse_IncRefEx(buff);
    else if (_T('}') == flag)
    {
        CseObj vDict = CseDict_new();
        TStolenObj ret(vDict);
        int index = 1;
        int iLen = CSE_ARRAY_LEN(buff->bValue);
        while (index < iLen)
        {
            CseObj key = buff->bValue[index-1];
            CseDict_set(ret,key,buff->bValue[index]);
            index += 2;
        }
        return Cse_IncRefEx(ret);
    }
    else if (_T(')') == flag)
    {
        int iLen = CSE_ARRAY_LEN(buff->bValue);
        TStolenObj ret(CseTier_new(iLen));
        for (int index = 0; index < iLen; index++)
            ret->tValue[index] = CseNum_AsInt(buff->bValue[index]);
        return Cse_IncRefEx(ret);
    }
    else if (_T('>') == flag)
    {
        int iLen = CSE_ARRAY_LEN(buff->bValue);
        if (iLen <= 0)
            return CseInstance_new();
        else
        {
            TStolenObj ret(CseNotator_new(buff->bValue[0]));
            for (int index = 1; index < iLen; index++)
                CseBuff_append(ret,buff->bValue[index]);
            return Cse_IncRefEx(ret);
        }
    }
    else throw LogObjBuildErr();
}

STATIC CseObj CreateByFmt(const TXchar *format, va_list& pArg)
{
    // first try quick access for most common build
    const TXchar *pCh = format;
    TXchar ch = format[1];
    if (ch == _T(']') && *pCh == _T('['))
        return CseBuff_new(0);
    else if (ch == _T('}') && *pCh == _T('{'))
        return CseDict_new();
    else if (ch == _T(')') && *pCh == _T('('))
        return CseTier_new(0);
    else if (ch == _T('>') && *pCh == _T('<'))
        return CseInstance_new();
    else if (*pCh == _T('%'))
    {
        pCh++;
        TStolenObj obj;
        BuildOneCseObj(obj,_T('%'),*pCh,pArg);
        return Cse_IncRefEx(obj);
    }
    else if (ch == _T('\0'))
    {
        TStolenObj obj;
        BuildOneCseObj(obj,_T('\0'),*pCh,pArg);
        return Cse_IncRefEx(obj);
    }

    // then process normal build
    TStolenObj holder(dummy);
    TStolenObj owners(CseBuff_new(0));
    CseObj owner_ = dummy;
    TCharArray OwnerTypes;

    TXchar prefix = _T('\0');
    while (*pCh != _T('\0'))
    {
        while (*pCh == _T(',')) pCh++;   // ignore ","
        if (*pCh == _T('%'))
        {
            prefix = _T('%');
            pCh++;
        }
        else prefix = _T('\0');
        
        TXchar flag = BuildOneCseObj(holder,prefix,*pCh,pArg);
        pCh++;

        if (owner_ == dummy) // if no receiver, just return single value
        {
            if (flag == _T(']') || flag == _T('}') || flag == _T(')') || flag == _T('>'))
                throw LogObjBuildErr();
            else if (flag == _T('[') || flag == _T('{') || flag == _T('(') || flag == _T('<'))
            {
                CseBuff_append(owners,holder);
                owner_ = holder;
                OwnerTypes += flag;
            }
            else return Cse_IncRefEx(holder);
        }
        else
        {
            if (flag == _T('\0')) // holder is single value, and owner_ must be buff
            {
                CseBuff_append(owner_,holder);
            }
            else if (flag == _T('[') || flag == _T('{') || flag == _T('(') || flag == _T('<'))
            {
                CseBuff_append(owners,holder);
                owner_ = holder;
                OwnerTypes += flag;
            }
            else
            {
                ASSERT_TRUE(flag == _T(']') || flag == _T('}') || flag == _T(')') || flag == _T('>'));

                int TypesLen = OwnerTypes.len();
                if (TypesLen > 0)
                {
                    TXchar LastFlag = OwnerTypes[TypesLen - 1];
                    if ( (flag == _T(']') && LastFlag != _T('[')) ||
                         (flag == _T('}') && LastFlag != _T('{')) ||
                         (flag == _T(')') && LastFlag != _T('(')) ||
                         (flag == _T('>') && LastFlag != _T('<')) )
                        throw LogObjBuildErr();
                    else OwnerTypes.truncate(TypesLen-1);
                }
                else throw LogObjBuildErr();

                TStolenObj item(SetupBuildResult(flag,owner_));

                int iLen = CSE_ARRAY_LEN(owners->bValue);
                ASSERT_TRUE(iLen > 0);
                if (iLen == 1)
                {
                    CseBuff_remove(owners,0);
                    return Cse_IncRefEx(item);
                }
                else
                {   // popup one owner level
                    CseBuff_remove(owners,iLen-1);
                    owner_ = owners->bValue[iLen-1]; // owner must be buff
                    ASSERT_TRUE(CSE_TYPE(owner_) == dtBuff);
                    CseBuff_append(owner_,item);
                }
            }
        }
    }

    // build nothing or not normal closed by ']','}',')','>'
    throw LogObjBuildErr();
}

TCseObj TCseObj::format(const TXchar *frmt, ...)
{
    va_list pArg;
    va_start(pArg, frmt);
    TStolenObj v(CreateByFmt(frmt,pArg));
    va_end(pArg);

    return TCseObj((CseObj)v);
}

TCseObj::TCseObj(const TIntObj& iObj)
{
    m_data = CseInt_new(iObj);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TWintObj& wObj)
{
    m_data = CseWint_new(wObj);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TFloatObj& fObj)
{
    m_data = CseFloat_new(fObj);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TCharArray& s)
{
    m_data = CseStr_new(s);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TIntArray& t)
{
    m_data = CseTier_new(t);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TObjArray& b)
{
    m_data = CseBuff_new(b);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TEntryArray& d)
{
    m_data = CseDict_new(d);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::~TCseObj()
{
    Cse_DecRef(m_data);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount--;
#endif
}

TCseObj::TCseObj(int MagicNum, TCharArray& s)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseStr_NewEx(s);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(int MagicNum, TIntArray& t)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseTier_NewEx(t);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(int MagicNum, TObjArray& b)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseBuff_NewEx(b);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj::TCseObj(int MagicNum, TEntryArray& d)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseDict_NewEx(d);
#ifndef CLOSE_REF_CHECK
    gTotalCseObjCount++;
#endif
}

TCseObj& TCseObj::operator=(const TCseObj& obj)
{
    CseObj v = m_data;
    m_data = Cse_IncRefEx(obj.m_data);
    Cse_DecRef(v);
    
    return *this;
}

TCseObj& TCseObj::operator=(CseObj obj)
{
    if (NULL == obj) obj = dummy;

    CseObj v = m_data;
    m_data = Cse_IncRefEx(obj);
    Cse_DecRef(v);

    return *this;
}

TBool TCseObj::operator==(TCseObj& obj) const
{
    return Cse_equal(Cse_unlink(m_data),Cse_unlink(obj));
}

TBool TCseObj::operator!=(TCseObj& obj) const
{
    return ! Cse_equal(Cse_unlink(m_data),Cse_unlink(obj));
}

TBool TCseObj::operator>(TCseObj& obj) const
{
    return compare(obj) > 0;
}

TBool TCseObj::operator>=(TCseObj& obj) const
{
    return compare(obj) >= 0;
}

TBool TCseObj::operator<(TCseObj& obj) const
{
    return compare(obj) < 0;
}

TBool TCseObj::operator<=(TCseObj& obj) const
{
    return compare(obj) <= 0;
}

TCseObj::operator CseObj() const
{
    return Cse_unlink(m_data);
}

CseObj TCseObj::operator->() const
{
    return Cse_unlink(m_data);
}

TCharArray IllegalCallDesc(const TXchar* sFunc)
{
    return TCharArray::format(_T("illegal function call: TCseObj.%s()"),sFunc);
}

TIntObj& TCseObj::iObj() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtInt == CSE_TYPE(data),IllegalCallDesc(_T("iObj")));
    return (TIntObj&) data->iValue;
}

TWintObj& TCseObj::wObj() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtWint == CSE_TYPE(data),IllegalCallDesc(_T("wObj")));
    return (TWintObj&) data->wValue;
}

TFloatObj& TCseObj::fObj() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtFloat == CSE_TYPE(data),IllegalCallDesc(_T("fObj")));
    return (TFloatObj&) data->fValue;
}

TCharArray& TCseObj::sArray() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtStr == CSE_TYPE(data),IllegalCallDesc(_T("sArray")));
    return (TCharArray&) data->sValue;
}

TIntArray& TCseObj::tArray() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtTier == CSE_TYPE(data),IllegalCallDesc(_T("tArray")));
    return (TIntArray&) data->tValue;
}

TObjArray& TCseObj::bArray() const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG(tp == dtBuff || tp >= dtNotator,IllegalCallDesc(_T("bArray")));
    return (TObjArray&) data->bValue;
}

TEntryArray& TCseObj::dArray() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == CSE_TYPE(data),IllegalCallDesc(_T("dArray")));
    return (TEntryArray&) data->entry;
}

TCseObj& TCseObj::assign(CseObj obj)
{
    if (NULL == obj) obj = dummy;

    CseObj v = m_data;
    m_data = Cse_IncRefEx(obj);
    Cse_DecRef(v);

    return *this;
}

int TCseObj::len() const
{
    return Cse_len(m_data);
}

void TCseObj::clear() const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG(dtBuff == tp || dtInstance == tp || dtDict == tp || dtStr == tp || dtTier == tp,IllegalCallDesc(_T("clear")));
    
    if (dtStr == tp)
        CseStr_clear(data);
    else if (dtTier == tp)
        CseTier_clear(data);
    else if (dtDict == tp)
        CseDict_clear(data);
    else CseBuff_clear(data);
}

int TCseObj::fixSize(int iRsvd) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG(dtStr == tp || dtTier == tp || dtBuff == tp || dtDict == tp,IllegalCallDesc(_T("fixSize")));

    if (Cse_FixSize(data,iRsvd))
        return 1;
    else return 0;
}

void TCseObj::join(const TCseObj& obj, int index) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp || dtDict == tp ||
               dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("join")));

    CseObj v = Cse_unlink(obj.m_data);
    if (dtStr == tp)
    {
        CHECK_MSG(dtStr == CSE_TYPE(v),IllegalCallDesc(_T("join")));
        CseStr_join(data,v,index);
    }
    else if (dtTier == tp)
    {
        CHECK_MSG(dtTier == CSE_TYPE(v),IllegalCallDesc(_T("join")));
        CseTier_join(data,v,index);
    }
    else if (dtDict == tp)
    {
        CHECK_MSG(dtDict == CSE_TYPE(v),IllegalCallDesc(_T("join")));
        CseDict_join(data,v);
    }
    else
    {
        tp = CSE_TYPE(v);
        CHECK_MSG(dtBuff == tp || dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("join")));
        CseBuff_join(data,v,index);
    }
}

TCseObj TCseObj::slice(int index, int len) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
                dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("slice")));

    if (dtStr == tp)
    {
        TStolenObj v(CseStr_slice(data,index,len));
        return (CseObj) v;
    }
    else if (dtTier == tp)
    {
        TStolenObj v(CseTier_slice(data,index,len));
        return (CseObj) v;
    }
    else
    {
        TStolenObj v(CseBuff_slice(data,index,len));
        return (CseObj) v;
    }
}

const TCseObj& TCseObj::append(const TCseObj& obj) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
                dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("append")));

    if (dtStr == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = CSE_TYPE(obj_);
        if (tp == dtInt)
            CseStr_append(data,(TXchar)obj_->iValue,NULL);
        else if (tp == dtWint)
            CseStr_append(data,(TXchar)obj_->wValue,NULL);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only char can append to string"));
    }
    else if (dtTier == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = CSE_TYPE(obj_);
        if (tp == dtInt)
            CseTier_append(data,obj_->iValue,NULL);
        else if (tp == dtWint)
            CseTier_append(data,(TInt)obj_->wValue,NULL);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only int can append to tier"));
    }
    else CseBuff_append(data,obj.m_data,NULL);
    
    return obj;
}

const TCseObj& TCseObj::insert(int index, const TCseObj& obj) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
               dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("insert")));

    if (dtStr == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = CSE_TYPE(obj_);
        if (tp == dtInt)
            CseStr_insert(data,index,(TXchar)obj_->iValue);
        else if (tp == dtWint)
            CseStr_insert(data,index,(TXchar)obj_->wValue);
        else if (tp == dtFloat)
            CseStr_insert(data,index,(TXchar)obj_->fValue);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only char can insert to string"));
    }
    else if (dtTier == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = CSE_TYPE(obj_);
        if (tp == dtInt)
            CseTier_insert(data,index,obj_->iValue);
        else if (tp == dtWint)
            CseTier_insert(data,index,(TInt)obj_->wValue);
        else if (tp == dtFloat)
            CseTier_insert(data,index,(TInt)obj_->fValue);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only int can insert to tier"));
    }
    else
    {
        CHECK_MSG(dtBuff == tp || index != 0,IllegalCallDesc(_T("insert")));
        CseBuff_insert(data,index,obj.m_data);
    }

    return obj;
}

void TCseObj::remove(int index, int len) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
               dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("remove")));

    if (dtStr == tp)
        CseStr_remove(data,index,len);
    else if (dtTier == tp)
        CseTier_remove(data,index,len);
    else
    {
        CHECK_MSG(dtBuff == tp || dtInstance == tp || index != 0,IllegalCallDesc(_T("remove")));
        CseBuff_remove(data,index,len);
    }
}

int TCseObj::truncate(int iLen) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
               dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("truncate")));

    if (dtStr == tp)
        return CseStr_truncate(data,iLen);
    else if (dtTier == tp)
        return CseTier_truncate(data,iLen);
    else if (dtBuff == tp)
        return CseBuff_truncate(data,iLen);
    else
    {
        CHECK_MSG(iLen >= 1,IllegalCallDesc(_T("truncate")));
        return CseBuff_truncate(data,iLen);
    }
}

void TCseObj::sort() const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp,IllegalCallDesc(_T("sort")));

    if (dtStr == tp)
        CseStr_sort(data);
    else if (dtTier == tp)
        CseTier_sort(data);
    else CseBuff_sort(data);
}

int TCseObj::type() const
{
    return CSE_TYPE(Cse_unlink(m_data));
}

TCharArray TCseObj::str() const
{
    TCharArray ret;
    CseObj data = Cse_unlink(m_data);
    Cse_str(ret,data);
    return TCharArray(CUT_FROM,ret);
}

TCharArray TCseObj::beStr() const
{
    TCharArray ret;
    CseObj data = Cse_unlink(m_data);
    Cse_BeStr(ret,data);
    return TCharArray(CUT_FROM,ret);
}

TUint32 TCseObj::hash() const
{
    CseObj data = Cse_unlink(m_data);
    return Cse_hash(data);
}

int TCseObj::compare(CseObj other) const
{
    CseObj data = Cse_unlink(m_data);

    // dummy value will shortcut comparsion
    if (data == dummy)
    {
        if (other == dummy)
            return 0;
        else return (int)data - (int)other;
    }
    else if (other == dummy)
        return (int)data - (int)other;

    else return Cse_ObjComp(data,other,CSE_TYPE(other));
}

CseObj TCseObj::transfer(const TCseObj& value)
{
    CseObj ret = m_data;
    m_data = Cse_IncRefEx(value.m_data);
    
    return ret;
}

void TCseObj::exchange(TCseObj& other)
{
    TStolenObj tmp(m_data);        // wait to release
    m_data = Cse_IncRefEx(other.m_data);

    TStolenObj tmp2(other.m_data); // wait to release
    other.m_data = Cse_IncRefEx((CseObj)tmp);
}

TBool TCseObj::isMapped() const
{
    return CSE_TYPE(m_data) == dtInstance;
}

TBool TCseObj::isLinked() const
{
    return Cse_OptionOn(m_data,CSEOBJ_LINKED);
}

TInt32 TCseObj::getFlag() const
{
    return Cse_GetFlag(Cse_unlink(m_data));
}

void TCseObj::setFlag(TInt32 flag) const
{
    Cse_SetFlag(Cse_unlink(m_data),flag);
}

TBool TCseObj::optionOn(int iBit) const
{
    return Cse_OptionOn(Cse_unlink(m_data),iBit);
}

void TCseObj::setOption(int iBit) const
{
    Cse_SetOption(Cse_unlink(m_data),iBit);
}

void TCseObj::clearOption(int iBit) const
{
    Cse_ClearOption(Cse_unlink(m_data),iBit);
}

TCseObj TCseObj::toId() const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    if (tp == dtId) return data;

    CHECK_MSG(tp == dtStr,IllegalCallDesc(_T("toId")));
    if (CSE_ARRAY_LEN(data->sValue) == 0)
        throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("try transfer empty string to ID"));

    TCharArray *s = (TCharArray *) &data->sValue;
    if (data == m_data && Cse_RefCount(m_data) == 1)
    {   // quick stolen from current string
        TStolenObj ret(CseId_NewEx(*s));
        return (CseObj) ret;
    }
    else
    {
        TStolenObj ret(CseId_new(*s));
        return (CseObj) ret;
    }
}

TCseObj& TCseObj::operator[](int index) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG( dtBuff == tp || dtInstance == tp || tp >= dtNotator,_T("illegal function call: TCseObj[]"));

    TObjArray *pBuff = (TObjArray*)&data->bValue;
    return pBuff->sub(index);
}

TCseObj& TCseObj::sub(int index) const
{
    int tp = CSE_TYPE(m_data);
    CHECK_MSG(dtBuff == tp || dtInstance == tp || tp >= dtNotator,IllegalCallDesc(_T("sub")));

    TObjArray *pBuff = (TObjArray *)&m_data->bValue;
    return pBuff->sub(index);
}

TCseObj TCseObj::pop(int index) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(CSE_TYPE(data) == dtBuff,IllegalCallDesc(_T("pop")));

    TObjArray *ObjArray = (TObjArray *) &data->bValue;
    return ObjArray->pop(index);
}

int TCseObj::push(const TCseObj& obj) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(CSE_TYPE(data) == dtBuff,IllegalCallDesc(_T("push")));

    int iRet = 0;
    TObjArray& bValue = (TObjArray&) data->bValue;
    bValue.add(obj,&iRet);

    return iRet + 1;
}

TCseObj TCseObj::toNotator(int index) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = CSE_TYPE(data);
    CHECK_MSG(tp == dtBuff || tp >= dtNotator || tp == dtInstance,IllegalCallDesc(_T("toNotator")));

    TStolenObj ret(CseBuff_ToNotator(data,index));
    return (CseObj) ret;
}

TBool TCseObj::isSpace() const
{
    CseObj data = Cse_unlink(m_data);
    return CSE_TYPE(data) == dtDict && data->entry != NULL && data->entry[0].key == constSpace;
}

TCseObj TCseObj::get(const TCseObj& key) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == CSE_TYPE(data),IllegalCallDesc(_T("get")));
    
    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->get(key);
}

const TCseObj& TCseObj::set(const TCseObj& key, const TCseObj& value) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG( dtDict == CSE_TYPE(data),IllegalCallDesc(_T("set")));
    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->set(key,value);
}

TCseObj TCseObj::quickGet(const TCseObj& key) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == CSE_TYPE(data),IllegalCallDesc(_T("quickGet")));
    CseObj key_ = Cse_unlink(key.m_data);
    CHECK_MSG(dtId == CSE_TYPE(key_),_T("key type of TCseObj.quickGet(key) invalid"));

    TUint32 hash = key_->hash;
    if (hash < CSE_ARRAY_LEN(data->entry))
    {
        PEntryPoint pEntry = data->entry + hash;
        if (pEntry->key == key_)
            return pEntry->value;
    }
    return dummy;
}

TBool TCseObj::quickSet(const TCseObj& key, const TCseObj& value) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == CSE_TYPE(data),IllegalCallDesc(_T("quickSet")));

    if (value == dummy)
    {   // delete key
        TEntryArray *EntryArray = (TEntryArray *) &data->entry;
        EntryArray->set(key,dummy);
        return true;
    }

    CseObj key_ = Cse_unlink(key.m_data);
    CHECK_MSG(dtId == CSE_TYPE(key_),_T("key type of TCseObj.quickSet(key,value) invalid"));

    TUint32 hash = key_->hash;
    PEntryPoint pEntry = data->entry + hash;
    if (pEntry->key == NULL)
    {
        CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *) ((char *)data->entry - sizeof(CSE_DICT_EXT));

        pEntry->value = Cse_IncRefEx(value.m_data);
        pEntry->key = Cse_IncRefEx(key_);
        pEntry->hash = hash;

        pDictExt->FilledCount++;
        pDictExt->count++;

        return true;
    }
    else return false;
}

TCseObj TCseObj::getEx(const TCseObj& key, const TCseObj& vDefault) const
{
    CseObj data = Cse_unlink(m_data);
    ASSERT_TRUE(dtDict == CSE_TYPE(data));

    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->getEx(key,vDefault);
}

TCseObj TCseObj::setEx(const TCseObj& key, const TCseObj& value) const
{
    CseObj data = Cse_unlink(m_data);
    ASSERT_TRUE(dtDict == CSE_TYPE(data));

    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->setEx(key,value);
}

TBool TCseObj::enumItem(PEntryPoint& pEntry, TCseObj *pKey, TCseObj *pValue) const
{
    CseObj data = Cse_unlink(m_data);
    ASSERT_TRUE(dtDict == CSE_TYPE(data));

    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->enumItem(pEntry,pKey,pValue);
}

TCseObj TCseObj::strongGet() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtStrong == CSE_TYPE(data),IllegalCallDesc(_T("strongGet")));
    return data->vValue;
}

const TCseObj& TCseObj::strongSet(const TCseObj& value) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtStrong == CSE_TYPE(data),IllegalCallDesc(_T("strongSet")));
    CseStrong_set(data,value.m_data);
    return value;
}

TCseObj CSE_HOLD(CseObj obj)
{
    return obj;
}

int CsePrint()
{
    return PRINTF(_T("\n"));
}

int CsePrint(const TCseObj& p0)
{
    TCharArray s = p0.beStr();
    return PRINTF(_T("%s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8, const TCseObj& p9)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    s += _T(' ') + p9.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8, const TCseObj& p9, const TCseObj& p10)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    s += _T(' ') + p9.beStr();
    s += _T(' ') + p10.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8, const TCseObj& p9, const TCseObj& p10, const TCseObj& p11)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    s += _T(' ') + p9.beStr();
    s += _T(' ') + p10.beStr();
    s += _T(' ') + p11.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8, const TCseObj& p9, const TCseObj& p10, const TCseObj& p11, const TCseObj& p12)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    s += _T(' ') + p9.beStr();
    s += _T(' ') + p10.beStr();
    s += _T(' ') + p11.beStr();
    s += _T(' ') + p12.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8, const TCseObj& p9, const TCseObj& p10, const TCseObj& p11, const TCseObj& p12, const TCseObj& p13)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    s += _T(' ') + p9.beStr();
    s += _T(' ') + p10.beStr();
    s += _T(' ') + p11.beStr();
    s += _T(' ') + p12.beStr();
    s += _T(' ') + p13.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8, const TCseObj& p9, const TCseObj& p10, const TCseObj& p11, const TCseObj& p12, const TCseObj& p13, const TCseObj& p14)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    s += _T(' ') + p9.beStr();
    s += _T(' ') + p10.beStr();
    s += _T(' ') + p11.beStr();
    s += _T(' ') + p12.beStr();
    s += _T(' ') + p13.beStr();
    s += _T(' ') + p14.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}

int CsePrint(const TCseObj& p0, const TCseObj& p1, const TCseObj& p2, const TCseObj& p3, const TCseObj& p4, const TCseObj& p5, const TCseObj& p6, const TCseObj& p7, const TCseObj& p8, const TCseObj& p9, const TCseObj& p10, const TCseObj& p11, const TCseObj& p12, const TCseObj& p13, const TCseObj& p14, const TCseObj& p15)
{
    TCharArray s = p0.beStr();
    s += _T(' ') + p1.beStr();
    s += _T(' ') + p2.beStr();
    s += _T(' ') + p3.beStr();
    s += _T(' ') + p4.beStr();
    s += _T(' ') + p5.beStr();
    s += _T(' ') + p6.beStr();
    s += _T(' ') + p7.beStr();
    s += _T(' ') + p8.beStr();
    s += _T(' ') + p9.beStr();
    s += _T(' ') + p10.beStr();
    s += _T(' ') + p11.beStr();
    s += _T(' ') + p12.beStr();
    s += _T(' ') + p13.beStr();
    s += _T(' ') + p14.beStr();
    s += _T(' ') + p15.beStr();
    return PRINTF(_T("%s %s\n"),s.addr());
}
